package cn.ecut.dzy.array;

import org.junit.Test;

import java.util.HashMap;

/**
 * @program: datastructure
 * @description:给定一个整数数组 nums 和一个整数目标值 target，请你在该数组中找出 和为目标值 target  的那 两个 整数，并返回它们的数组下标。
 * <p>
 * 你可以假设每种输入只会对应一个答案。但是，数组中同一个元素在答案里不能重复出现。
 * <p>
 * 你可以按任意顺序返回答案。
 * @create: 2021-10-31 15:18
 **/

public class TwoSum {


    @Test
    // 方法一：暴力法，穷举所有两数组合
    public int[] twoSum1(int[] nums, int target) {
        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if ((nums[i] + nums[j] == target)) {
                    return new int[]{i, j};
                }
            }
        }
        // 如果找不到，抛出异常
        throw new IllegalArgumentException("no solution");
    }

    // 方法二：哈希表保存所有数的信息
    public int[] twoSum2(int[] nums, int target) {
        int n = nums.length;

        // 定义一个哈希表
        HashMap<Integer, Integer> map = new HashMap<>();
        // 1. 遍历数组，将数据全部保存入hash表
        for (int i = 0; i < n; i++) {
            map.put(nums[i], i);
        }
        // 2. 再次遍历数组，寻找每个数对应的那个数是否存在
        for (int i = 0; i < n; i++) {
            int thatNum = target - nums[i];
            // 如果那个数存在，并且不是当前数自身，就直接返回结果
            if (map.containsKey(thatNum) && map.get(thatNum) != i) {
                return new int[]{i, map.get(thatNum)};
            }
        }
        // 如果找不到，抛出异常
        throw new IllegalArgumentException("no solution");
    }

    // 方法三：改进，遍历一次哈希表
    public int[] twoSum3(int[] nums, int target) {
        int n = nums.length;
        // 定义一个哈希表
        HashMap<Integer, Integer> map = new HashMap<>();
        // 遍历数组，寻找每个数对应的那个数是否存在（只向前寻找）
        for (int i = 0; i < n; i++) {
            int thatNum = target - nums[i];
            // 如果那个数存在，并且不是当前数自身，就直接返回结果
            if (map.containsKey(thatNum)) {
                return new int[]{map.get(thatNum), i};
            }
            map.put(nums[i], i);
            //System.out.println(map);

        }
        // 如果找不到，抛出异常
        throw new IllegalArgumentException("no solution");
    }

    public static void main(String[] args) {
        int[] input = {2, 7, 11, 15};
        int[] input2 = {3, 1, 3};
        int[] input4 = {3, 3, 7,1,10};
        int target = 9;
        int target2 = 6;
        int target4 = 8;

        // 定义一个大数组，进行性能测试
        int[] input3 = new int[1000000];
        for (int i = 0; i < input3.length; i++)
            input3[i] = input3.length - i;

        int target3 = 567890;

        // 为了计算程序运行时间，开始计算和计算完成分别计时
        long startTime = System.currentTimeMillis();

        TwoSum twoSum = new TwoSum();
        //int[] output = twoSum.twoSum1(input2, target2);
        int[] output = twoSum.twoSum3(input4, target4);

        long endTime = System.currentTimeMillis();

        System.out.println("程序运行时间：" + (endTime - startTime) + "ms");

        for (int index : output)
            System.out.print(index + "\t");
    }
}
